package base

import (
	"errors"
	"log"
	"runtime"
	"strconv"
)

/*
错误处理
*/

// 定义若干常见错误类型
var (
	ErrBadParam  = errors.New("请求参数错误")
	ErrNotFound  = errors.New("未找到指定的数据")
	ErrFinished  = errors.New("活动已结束")
	ErrForbidden = errors.New("没有访问指定数据的权限")
	ErrInternal  = errors.New("内部错误")
)

// Wrap 允许对常见的错误类型进行包装，使用不同的错误提示
func Wrap(err error, msg string) error {
	return &wrapError{
		err: err,
		msg: msg,
	}
}

type wrapError struct {
	err error
	msg string
}

func (e *wrapError) Error() string {
	return e.msg
}

func (e *wrapError) Unwrap() error {
	return e.err
}

// LocatedError 是内部用的错误类型，提供错误的原始定位
type LocatedError struct {
	pc   uintptr
	file string
	line int
	err  error
}

func (l LocatedError) Error() string {
	return l.err.Error()
}

func (l LocatedError) String() string {
	return l.file + ":" + strconv.Itoa(l.line) + ":" + l.Error()
}

func (l LocatedError) Unwrap() error {
	return l.err
}

/*
错误处理工具
可以略微增加开发效率，但会略微影响性能，略微影响观感

func Marshal(v any) (data string, err error) {
	defer Message(&err)                          // 拦截以panic形式返回的error，不拦截panic会向上传递
	return string(Must2(json.Marshal(v))), nil // Must2第二个参数是error，如果不为空则抛出panic
}
*/

// Log 拦截panic，如果是error则输出到日志，否则继续抛出
func Log() {
	info := recover()
	if info != nil {
		if _err, ok := info.(LocatedError); ok {
			_, _ = log.Writer().Write([]byte(_err.String()))
			return
		} else if _err, ok := info.(error); ok {
			pc, file, line, _ := runtime.Caller(2)
			_, _ = log.Writer().Write([]byte(LocatedError{
				pc:   pc,
				file: file,
				line: line,
				err:  _err,
			}.String()))
			return
		} else {
			panic(info)
		}
	}
}

// Error 拦截panic，如果是error则给err赋值，否则继续抛出
func Error(err *error) {
	info := recover()
	if info != nil {
		if _err, ok := info.(LocatedError); ok {
			*err = _err
			return
		} else if _err, ok := info.(error); ok {
			pc, file, line, _ := runtime.Caller(2)
			*err = LocatedError{
				pc:   pc,
				file: file,
				line: line,
				err:  _err,
			}
		} else {
			panic(info)
		}
	}
}

// Must 检查输入的error值，如果不为空则抛出panic
func Must(err error) {
	if err != nil {
		if _err, ok := err.(LocatedError); ok {
			panic(_err)
		} else {
			pc, file, line, _ := runtime.Caller(1)
			panic(LocatedError{
				pc:   pc,
				file: file,
				line: line,
				err:  err,
			})
		}
	}
}

// Must2 检查第二个参数error是否为空，如果不为空则抛出panic，否则返回正常的值
func Must2[T any](v T, err error) T {
	if err != nil {
		if _err, ok := err.(LocatedError); ok {
			panic(_err)
		} else {
			pc, file, line, _ := runtime.Caller(1)
			panic(LocatedError{
				pc:   pc,
				file: file,
				line: line,
				err:  err,
			})
		}
	}
	return v
}

func Must3[T1, T2 any](v1 T1, v2 T2, err error) (T1, T2) {
	if err != nil {
		if _err, ok := err.(LocatedError); ok {
			panic(_err)
		} else {
			pc, file, line, _ := runtime.Caller(1)
			panic(LocatedError{
				pc:   pc,
				file: file,
				line: line,
				err:  err,
			})
		}
	}
	return v1, v2
}

func Cover(err error, msg string) {
	if err != nil {
		panic(Wrap(ErrInternal, msg))
	}
}

func CoverBindParamsError(err error) {
	if err != nil {
		log.Println("CoverBindParamsError", err)
		panic(Wrap(ErrBadParam, "解析参数失败"))
	}
}

func Check2[V any](v V, err error) (res *checkResult2[V]) {
	//if err != nil && err != ErrForbidden {
	//	if _, ok := err.(LocatedError); !ok {
	//		pc, file, line, _ := runtime.Caller(1)
	//		err = LocatedError{
	//			pc:   pc,
	//			file: file,
	//			line: line,
	//			err:  err,
	//		}
	//	}
	//}
	return &checkResult2[V]{err, v}
}

type checkResult2[T any] struct {
	err error
	v   T
}

// Cover 当返回错误时，在外面包装一层后抛出
func (res *checkResult2[V]) Cover(msg string) V {
	if res.err != nil {
		panic(Wrap(ErrInternal, msg))
	}
	return res.v
}

func (res *checkResult2[V]) Internal(msg ...string) V {
	if res.err != nil {
		msg = append(msg, "内部错误")
		panic(Wrap(ErrInternal, msg[0]))
	}
	return res.v
}

func (res *checkResult2[V]) BadParam(msg ...string) V {
	if res.err != nil {
		log.Println("BadParam", res.err.Error())
		msg = append(msg, "解析参数失败")
		panic(Wrap(ErrBadParam, msg[0]))
	}
	return res.v
}

func (res *checkResult2[V]) CoverIdIsEmpty() V {
	if res.err != nil {
		panic(Wrap(ErrBadParam, "id不能为空"))
	}
	return res.v
}

func Check3[V1, V2 any](v1 V1, v2 V2, err error) (res *checkResult3[V1, V2]) {
	//if err != nil {
	//	if _, ok := err.(LocatedError); !ok {
	//		pc, file, line, _ := runtime.Caller(1)
	//		err = LocatedError{
	//			pc:   pc,
	//			file: file,
	//			line: line,
	//			err:  err,
	//		}
	//	}
	//}
	return &checkResult3[V1, V2]{err, v1, v2}
}

type checkResult3[V1, V2 any] struct {
	err error
	v1  V1
	v2  V2
}

// Cover 当返回错误时，在外面包装一层后抛出
func (res *checkResult3[V1, V2]) Cover(msg string) (V1, V2) {
	if res.err != nil {
		panic(res.err)
	}
	return res.v1, res.v2
}

func Check4[V1, V2, V3 any](v1 V1, v2 V2, v3 V3, err error) (res *checkResult4[V1, V2, V3]) {
	//if err != nil {
	//	if _, ok := err.(LocatedError); !ok {
	//		pc, file, line, _ := runtime.Caller(1)
	//		err = LocatedError{
	//			pc:   pc,
	//			file: file,
	//			line: line,
	//			err:  err,
	//		}
	//	}
	//}
	return &checkResult4[V1, V2, V3]{err, v1, v2, v3}
}

type checkResult4[V1, V2, V3 any] struct {
	err error
	v1  V1
	v2  V2
	v3  V3
}

// Cover 当返回错误时，在外面包装一层后抛出
func (res *checkResult4[V1, V2, V3]) Cover(msg string) (V1, V2, V3) {
	if res.err != nil {
		panic(res.err)
	}
	return res.v1, res.v2, res.v3
}

// Try2 接受并执行一个函数，如果函数返回err或抛出panic，则触发Catch,否则触发Then
func Try2[V any](h func() (v V, err error)) (res TryResult2[V]) {
	defer func() {
		if info := recover(); info != nil {
			res.info = info
		}
	}()
	v, err := h()
	return TryResult2[V]{err, v}
}

type TryResult2[T any] struct {
	info any
	v    T
}

func (res TryResult2[V]) Handle(h func(info any) V) V {
	if res.info != nil {
		res.v = h(res.info)
	}
	return res.v
}

type has struct {
	has bool
}

func (v has) NotFound(msg ...string) {
	if !v.has {
		msg = append(msg, "记录不存在")
		panic(Wrap(ErrNotFound, msg[0]))
	}
}

func Has(h bool) *has {
	return &has{h}
}

type assert struct {
	v bool
}

func (v assert) NotFound(msg string) {
	if v.v {
		panic(Wrap(ErrNotFound, msg))
	}
}

func (v assert) BadParam(msg string) {
	if v.v {
		panic(Wrap(ErrBadParam, msg))
	}
}

func (v assert) Forbidden(msg ...string) {
	if v.v {
		msg = append(msg, "没有操作权限")
		panic(Wrap(ErrForbidden, msg[0]))
	}
}

func When(v bool) *assert {
	return &assert{v}
}

func Ignore2[T any](v T, err error) T {
	return v
}

type empty[T comparable] struct {
	v T
}

//func Empty[T comparable](v T) *empty[T] {
//	return &empty[T]{v}
//}
//
//func (v empty[T]) BadParam(msg ...string) T {
//	isEmpty := false
//	switch v.v.(type) {
//	case string:
//		isEmpty = v.v == ""
//	}
//	if isEmpty {
//		msg = append(msg, "解析参数失败")
//		panic(Wrap(ErrBadParam, msg[0]))
//	}
//	return v.v
//}

//type Check2XS[T1, T2 any] struct {
//	v1  T1
//	v2  T2
//	res bool
//}
//
//func Check2X[T1, T2 any](v1 T1, v2 T2) (res Check2XS[T1, T2]) {
//	return Check2XS[T1, T2]{v1, v2, false}
//}
//
//func (s Check2XS[T1, bool]) False() Check2XS[T1, bool] {
//	s.res = s.v2.(bool) == false
//	return s
//}
//
//func (s Check2XS[T1, T2]) BadParam(msg string) T1 {
//	if !s.res {
//		panic(Wrap(ErrBadParam, msg))
//	}
//	return s.v1
//}
